package com.fcscs.cservice.service.impl;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.interceptor.TransactionAspectSupport;

import com.fcscs.core.common.ErrorEnums;
import com.fcscs.core.service.FcsManager;
import com.fcscs.core.util.CommonUtil;
import com.fcscs.cservice.common.CServiceCommonEnums;
import com.fcscs.cservice.common.CServiceCommonEnums.InRoomMenuType;
import com.fcscs.cservice.common.CServiceCommonEnums.PriceCategoryCodeEnum;
import com.fcscs.cservice.dao.InRoomCategoryDao;
import com.fcscs.cservice.dao.InRoomItemDao;
import com.fcscs.cservice.dao.InRoomItemPriceDao;
import com.fcscs.cservice.dao.InRoomMenuDao;
import com.fcscs.cservice.domain.InRoomCategory;
import com.fcscs.cservice.domain.InRoomItem;
import com.fcscs.cservice.domain.InRoomItemPrice;
import com.fcscs.cservice.domain.InRoomMenu;
import com.fcscs.cservice.domain.Versions;
import com.fcscs.cservice.domain.model.EntityVersionView;
import com.fcscs.cservice.domain.model.InRoomMenuModel;
import com.fcscs.cservice.domain.model.ItemView;
import com.fcscs.cservice.domain.validator.ECMSInRoomMenuValidators;
import com.fcscs.cservice.service.ECMSInRoomMenuManager;

@Service("ecmsInRoomMenuManager")
public class ECMSInRoomMenuManagerImpl extends FcsManager implements ECMSInRoomMenuManager {

	private static Logger LOGGER = Logger.getLogger(ECMSInRoomMenuManagerImpl.class);

	@Autowired
	InRoomItemDao iriDao;

	@Autowired
	InRoomCategoryDao ircDao;

	@Autowired
	InRoomItemPriceDao iripDao;

	@Autowired
	InRoomMenuDao irmDao;

	@Override
	public InRoomCategory getInRoomCategory(long id) {
		return ircDao.get(id);
	}
	
	public List<InRoomMenuModel> getInRoomMenuModels(long orgId, long propId) {
		List<InRoomMenu> menus = getInRoomMenuList(orgId, propId, true);
		List<InRoomMenuModel> models = new ArrayList<InRoomMenuModel>();
		for (InRoomMenu m : menus) {
			InRoomMenuModel mo = new InRoomMenuModel();
			mo.setCategoryId(m.getCategoryId());
			mo.setSubcategoryId(m.getSubcategoryId());
			mo.setItemId(m.getItemId());
			mo.setAutoSuggestionItemId(m.getAutoSuggestionItemId());
			mo.setDisplayOrder(m.getDisplayOrder());
			if (m.getAutoSuggestionItemId() != null) {
				InRoomItem item = iriDao.get(m.getAutoSuggestionItemId());
				mo.setTitle(item.getName());
				mo.setDescription(item.getDescription());
				mo.setImageId(item.getSmallImageId() == null ? null : item.getSmallImageId().longValue());
				mo.setType(InRoomMenuType.SUGGEST_ITEM);
			} else if (m.getItemId() != null) {
				InRoomItem item = iriDao.get(m.getItemId());
				mo.setTitle(item.getName());
				mo.setDescription(item.getDescription());
				mo.setImageId(item.getSmallImageId() == null ? null : item.getSmallImageId().longValue());
				mo.setType(InRoomMenuType.ITEM);
			} else if (m.getSubcategoryId() != null) {
				InRoomCategory cat = ircDao.get(m.getSubcategoryId());
				mo.setTitle(cat.getName());
				mo.setDescription(cat.getDescription());
				mo.setImageId(cat.getSmallImageId() == null ? null : cat.getSmallImageId().longValue());
				mo.setType(InRoomMenuType.SUBCATEGORY);
			} else {
				InRoomCategory cat = ircDao.get(m.getCategoryId());
				mo.setTitle(cat.getName());
				mo.setDescription(cat.getDescription());
				mo.setImageId(cat.getSmallImageId() == null ? null : cat.getSmallImageId().longValue());
				mo.setType(InRoomMenuType.CATEGORY);
			}
			models.add(mo);
		}
		return models;
	}
	
	public boolean saveInRoomMenuModels(long orgId, long propId, List<InRoomMenuModel> menu) {
		irmDao.permDeleteAll(orgId, propId);
		for (InRoomMenuModel m : menu) {
			InRoomMenu me = new InRoomMenu();
			me.setOrgId(orgId);
			me.setPropertyId(propId);
			me.setCategoryId(m.getCategoryId());
			me.setSubcategoryId(m.getSubcategoryId());
			me.setAutoSuggestionItemId(m.getAutoSuggestionItemId());
			me.setDisplayOrder(m.getDisplayOrder());
			me.setLevel(m.getType().getLevel());
			me = createInRoomMenu(me);
			if (me == null) {
				throw new RuntimeException();
			}
		}		
		return true;
	}

	@Override
	public List<InRoomCategory> getInRoomCategoryList(long orgId, long propId, int level, boolean isCurrent) {
		return ircDao.getInRoomCategoryList(orgId, propId, level, isCurrent);
	}

	@Override
	public List<InRoomCategory> getInRoomCategoryList(long orgId, long propId, long versionId, int level) {
		return ircDao.getInRoomCategoryList(orgId, propId, versionId, level);
	}

	@Override
	public InRoomCategory createInRoomCategory(InRoomCategory cat) {
		
		long orgId = CommonUtil.getUserContext().getOrgId();
		Long propertyId = CommonUtil.getUserContext().getPropertyId();
		cat.setOrgId(orgId);
		cat.setPropertyId(cat.getPropertyId() == null ? propertyId : cat.getPropertyId());
		transferBaseVals(cat, cat, true);
		ErrorEnums err = new ECMSInRoomMenuValidators.InRoomCategoryValidator().validate(cat, true);
		if (err != null) {
			LOGGER.warn(err);
			return null;
		}
		
		if (isInRoomCategoryTaken(orgId, cat.getPropertyId(), cat.getName(), null, cat.getVersionId(), cat.getLevel())) {
			LOGGER.warn(ErrorEnums.GeneralError.UNIQUE_CONS);
			return null;
		}
		
		ircDao.save(cat);
		return cat;
	}

	@Override
	public InRoomCategory saveInRoomCategory(InRoomCategory cat) {
		
		ErrorEnums err = new ECMSInRoomMenuValidators.InRoomCategoryValidator().validate(cat, false);
		if (err != null) {
			LOGGER.warn(err);
			return null;
		}
		
		InRoomCategory update = ircDao.get(cat.getId());
		
		if (isInRoomCategoryTaken(update.getOrgId(), update.getPropertyId(), cat.getName(), null, update.getVersionId(), update.getLevel())) {
			LOGGER.warn(ErrorEnums.GeneralError.UNIQUE_CONS);
			return null;
		}	
		transferInRoomCategoryVal(cat, update);
		transferBaseVals(update, update, false);
		ircDao.save(cat);
		return cat;
	}
	
	private void transferInRoomCategoryVal(InRoomCategory from, InRoomCategory to) {
		to.setAvailableFrom(from.getAvailableFrom());
		to.setAvailableTo(from.getAvailableTo());
		to.setCode(from.getCode());
		to.setDescription(from.getDescription());
		to.setDescriptionSecLang(from.getDescriptionSecLang());
		to.setDescriptionThdLang(from.getDescriptionThdLang());
		to.setLargeImageId(from.getLargeImageId());
		to.setmServiceImageId(from.getmServiceImageId());
		to.setName(from.getName());
		to.setNameSecLang(from.getNameSecLang());
		to.setNameThdLang(from.getNameThdLang());
		to.setPriceCategoryEnum(from.getPriceCategoryEnum());
		to.setSmallImageId(from.getSmallImageId());
	}

	@Override
	public boolean deleteInRoomCategory(InRoomCategory cat) {
		return ircDao.delete(cat);
	}

	@Override
	public void permDeleteInRoomCategory(InRoomCategory cat) {
		ircDao.permDelete(cat);
	}

	@Override
	public boolean isInRoomCategoryTaken(long orgId, long propId, String name, Long id, long versionId, int level) {
		return ircDao.isInRoomCategoryTaken(orgId, propId, name, id, versionId, level);
	}

	@Override
	public InRoomItem getInRoomItem(long id) {
		InRoomItem item = iriDao.get(id);
		item.setPrices(iripDao.getInRoomItemPrices(id));
		return item;
	}

	@Override
	public List<InRoomItem> getInRoomItemList(long orgId, long propId, boolean isCurrent) {
		return iriDao.getInRoomItemList(orgId, propId, isCurrent);
	}

	@Override
	public List<InRoomItem> getInRoomItemList(long orgId, long propId, long versionId) {
		return iriDao.getInRoomItemList(orgId, propId, versionId);
	}

	@Override
	public InRoomItem createInRoomItem(InRoomItem item) {

		long orgId = CommonUtil.getUserContext().getOrgId();
		Long propertyId = CommonUtil.getUserContext().getPropertyId();
		item.setOrgId(orgId);
		item.setPropertyId(item.getPropertyId() == null ? propertyId : item.getPropertyId());
		
		ErrorEnums err = new ECMSInRoomMenuValidators.InRoomItemValidator().validate(item, true);
		if (err != null) {
			LOGGER.warn(err);
			TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
			return null;
		}

		if (item.getPrices() == null || item.getPrices().size() == 0) {
			LOGGER.warn(ErrorEnums.GeneralError.REQURIED_FLD_MISSING);
			TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
			return null;
		}
		
		
		if (isPricesDuplicate(item.getPrices())) {
			LOGGER.warn(ErrorEnums.GeneralError.UNIQUE_CONS);
			TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
			return null;
		}
		
		List<InRoomItemPrice> nps = new ArrayList<InRoomItemPrice>();
		for (InRoomItemPrice price : item.getPrices()) {
			InRoomItemPrice p = new InRoomItemPrice();
			transferInRoomItemPrice(price, p);
			nps.add(p);
		}

		for (InRoomItemPrice price : nps) {
			price.setOrgId(orgId);
			price.setPropertyId(item.getPropertyId());
			
			ErrorEnums err3 = new ECMSInRoomMenuValidators.InRoomPriceValidator().validate(price, true);
			if (err3 != null) {
				LOGGER.warn(err3);
				TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
				return null;
			}
			
			transferBaseVals(price, price, true);
			iripDao.save(price);
		}
		item.setPrices(nps);

		if (isInRoomItemTaken(orgId, item.getPropertyId(), item.getName(), null, 0)) {
			TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
			LOGGER.warn(ErrorEnums.GeneralError.UNIQUE_CONS);
			return null;
		}

		transferBaseVals(item, item, true);
		iriDao.save(item);
		
		return item;
	}

	@Override
	public InRoomItem saveInRoomItem(InRoomItem item) {

		long orgId = CommonUtil.getUserContext().getOrgId();
		Long propertyId = CommonUtil.getUserContext().getPropertyId();
		item.setOrgId(orgId);
		item.setPropertyId(item.getPropertyId() == null ? propertyId : item.getPropertyId());

		ErrorEnums err1 = new ECMSInRoomMenuValidators.InRoomItemValidator().validate(item, false);
		if (err1 != null) {
			LOGGER.warn(err1);
			TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
			return null;
		}

		InRoomItem update = iriDao.get(item.getId());
		if (isInRoomItemTaken(update.getOrgId(), update.getPropertyId(), item.getName(), item.getId(), 0)) {
			LOGGER.warn(ErrorEnums.GeneralError.UNIQUE_CONS);
			TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
			return null;
		}


		if (item.getPrices() == null || item.getPrices().size() == 0) {
			LOGGER.warn(ErrorEnums.GeneralError.REQURIED_FLD_MISSING);
			TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
			return null;
		}
		
		
		if (isPricesDuplicate(item.getPrices())) {
			LOGGER.warn(ErrorEnums.GeneralError.UNIQUE_CONS);
			TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
			return null;
		}
		
		List<InRoomItemPrice> nps = new ArrayList<InRoomItemPrice>();
		for (InRoomItemPrice price : item.getPrices()) {
			InRoomItemPrice p = new InRoomItemPrice();
			transferInRoomItemPrice(price, p);
			nps.add(p);
		}
		iripDao.permDeletePrices(item.getId());
		
		for (InRoomItemPrice price : nps) {
			price.setOrgId(orgId);
			price.setPropertyId(item.getPropertyId());
			
			ErrorEnums err3 = new ECMSInRoomMenuValidators.InRoomPriceValidator().validate(price, true);
			if (err3 != null) {
				LOGGER.warn(err3);
				TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
				return null;
			}
			
			transferBaseVals(price, price, true);
			iripDao.save(price);
		}

		update.setPrices(nps);
		
		transferInRoomItem(item, update);
		transferBaseVals(update, update, false);
		iriDao.save(update);
		
		return update;
	}
	
	private void transferInRoomItemPrice(InRoomItemPrice from, InRoomItemPrice to) {
		to.setItemId(from.getItemId());
		to.setPrice(from.getPrice());
		to.setPriceCategoryEnum(from.getPriceCategoryEnum());
	}
	
	private void transferInRoomItem(InRoomItem from, InRoomItem to) {
		to.setChargeCategoryId(from.getChargeCategoryId());
		to.setCode(from.getCode());
		to.setDescription(from.getDescription());
		to.setDescriptionSecLang(from.getDescriptionSecLang());
		to.setDescriptionThdLang(from.getDescriptionThdLang());
		to.setLargeImageId(from.getLargeImageId());
		to.setLeadTime(from.getLeadTime());
		to.setName(from.getName());
		to.setNameSecLang(from.getNameSecLang());
		to.setNameThdLang(from.getNameThdLang());
		to.setSmallImageId(from.getSmallImageId());
		to.setTransactionTypeId(from.getTransactionTypeId());
	}
	
	private boolean isPricesDuplicate(List<InRoomItemPrice> prices) {
		Set<PriceCategoryCodeEnum> values = new HashSet<CServiceCommonEnums.PriceCategoryCodeEnum>();
		for (InRoomItemPrice p : prices) {
			if (values.contains(p.getPriceCategoryEnum())) {
				return true;
			}
			values.add(p.getPriceCategoryEnum());
		}
		return false;
	}

	@Override
	public boolean deleteInRoomItem(InRoomItem item) {
		return iriDao.delete(item);
	}

	@Override
	public void permDeleteInRoomItem(InRoomItem item) {
		iripDao.permDeletePrices(item.getId());
		iriDao.permDelete(item);
	}

	@Override
	public boolean isInRoomItemTaken(long orgId, long propId, String name, Long id, long versionId) {
		return iriDao.isInRoomItemTaken(orgId, propId, name, id, versionId);
	}

	@Override
	public List<ItemView> getInRoomItemViewList(long orgId, long propId, Long parentCategoryId, List<Long> itemIdList) {
		return null;
	}


	@Override
	public InRoomMenu getInRoomMenu(long id) {
		return irmDao.get(id);
	}

	@Override
	public List<InRoomMenu> getInRoomMenuList(long orgId, long propId, boolean isCurrent) {
		return irmDao.getInRoomMenuList(orgId, propId, 0);
	}

	@Override
	public List<InRoomMenu> getInRoomMenuList(long orgId, long propId, long versionId) {
		return irmDao.getInRoomMenuList(orgId, propId, versionId);
	}

	@Override
	public InRoomMenu createInRoomMenu(InRoomMenu menu) {
		long orgId = CommonUtil.getUserContext().getOrgId();
		Long propertyId = CommonUtil.getUserContext().getPropertyId();
		menu.setOrgId(orgId);
		menu.setPropertyId(menu.getPropertyId() == null ? propertyId : menu.getPropertyId());
		transferBaseVals(menu, menu, true);
		ErrorEnums err = new ECMSInRoomMenuValidators.InRoomMenuValidator().validate(menu, true);
		if (err != null) {
			LOGGER.warn(err);
			return null;
		}
		irmDao.save(menu);
		return menu;
	}

	@Override
	public InRoomMenu saveInRoomMenu(InRoomMenu menu) {
		
		long orgId = CommonUtil.getUserContext().getOrgId();
		Long propertyId = CommonUtil.getUserContext().getPropertyId();
		menu.setOrgId(orgId);
		menu.setPropertyId(menu.getPropertyId() == null ? propertyId : menu.getPropertyId());
		ErrorEnums err = new ECMSInRoomMenuValidators.InRoomMenuValidator().validate(menu, false);
		if (err != null) {
			LOGGER.warn(err);
			return null;
		}
		InRoomMenu update = irmDao.get(menu.getId());
		transferInRoomMenuVal(menu, update);

		if (isInRoomMenuTaken(orgId, menu.getPropertyId(), menu.getId(), menu.getCategoryId(), menu.getSubcategoryId(),
				menu.getItemId(), menu.getAutoSuggestionItemId(), 0)) {
			LOGGER.warn(ErrorEnums.GeneralError.UNIQUE_CONS);
			return null;
		}

		transferBaseVals(update, update, false);
		irmDao.save(update);
		return update;
	}

	private void transferInRoomMenuVal(InRoomMenu from, InRoomMenu to) {
		to.setCategoryId(from.getCategoryId());
		to.setSubcategoryId(from.getSubcategoryId());
		to.setItemId(from.getId());
		to.setAutoSuggestionItemId(to.getAutoSuggestionItemId());
		to.setLevel(from.getLevel());
		to.setDisplayOrder(from.getDisplayOrder());
	}

	@Override
	public boolean deleteInRoomMenu(InRoomMenu menu) {
		return irmDao.delete(menu);
	}

	@Override
	public void permDeleteInRoomMenu(InRoomMenu menu) {
		irmDao.permDelete(menu);
	}

	@Override
	public boolean isInRoomMenuTaken(long orgId, long propId, Long id, long categoryId, Long subcategoryId,
			Long itemId, Long autoSuggestionItemId, long versionId) {
		return irmDao.isInRoomMenuTaken(orgId, propId, id, categoryId, subcategoryId, itemId, autoSuggestionItemId,
				versionId);
	}
	
	@Override
	public boolean copyVersion(Versions fromVer, Versions toVer) {
		// TODO Auto-generated method stub
		return false;
	}

	@Override
	public List<EntityVersionView> getEntityVersionViewList(long orgId,
			long propId) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public List<EntityVersionView> findInRoomItemViewList(long orgId, long propId, Date deliveryTime, String term) {
		// TODO Auto-generated method stub
		return null;
	}
	
}
